﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Globalization;
using System.Web;

namespace FS4SPQueryStatistics
{
    public partial class Main : Form
    {
        
        public Main()
        {
            InitializeComponent();
            lnk_SL.Links.Add(0,14,"http://softlanding.ca");
        }
        public int TotalQueries = 0;
        public List<String> Users = new List<string>();
        public List<String> Dates = new List<string>();
        public List<String> Queries = new List<string>();
        public List<String> Sites = new List<string>();
        private void btn_Start_Click(object sender, EventArgs e)
        {
            //Code Borred from Mikael Svensons FAST Query Logger
            btn_Start.Enabled = false;
            if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("FASTSEARCH")))
            {
                MessageBox.Show("FAST for SharePoint is not installed");
                Environment.Exit(0);
            }

            try
            {
                // Try to read the log folder
                var logPath = Path.Combine(Environment.GetEnvironmentVariable("FASTSEARCH"), @"var\log\querylogs");
                DirectoryInfo di = new DirectoryInfo(logPath);
                FileSystemInfo[] fileSystemInfos = di.GetFileSystemInfos();
                status_ProgressBar.Maximum = fileSystemInfos.Length;

                if (fileSystemInfos.Length > 0)
                {
                    foreach (FileSystemInfo querylog in fileSystemInfos)
                    {
                        try
                        {
                            using (StreamReader sr = new StreamReader(querylog.FullName))
                            {
                                while (sr.Peek() >= 0)
                                {
                                    String LogLine = sr.ReadLine();
                                    if (LogLine.Length > 0)
                                    {
                                        if (DateTime.Compare(GetQueryDate(LogLine), Convert.ToDateTime(txt_DateFilter.Text)) > -1)
                                        {
                                            ProcessLog(LogLine);
                                        }
                                    }
                                }
                            }
                            status_ProgressBar.Value++;
                        }
                        catch (Exception EX)
                        {
                            if (!EX.Message.Contains("Length cannot be less than zero.") && !EX.Message.Contains("The process cannot access the file"))
                            {
                                MessageBox.Show(EX.ToString());
                            }
                        }
                    }
                    PostProcess();
                    status_ProgressBar.Value = 0;
                    btn_Start.Enabled = true;

                }
                else
                {
                    MessageBox.Show("No log files available");
                }
            }
            catch (Exception EX)
            {
                MessageBox.Show(EX.ToString());
                status_ProgressBar.Value = 0;
                btn_Start.Enabled = true;
            }
            }

        public void ProcessLog(String LogLine)
        {
            try
            {
                // Ignore lines that dont have a Security parameter, ie SCOM queries
                if (LogLine.Contains("&qtf_securityfql:uid="))
                {
                    // Total Queries
                    TotalQueries++;

                    // User UID                    
                    //String UserID = LogLine.Substring(LogLine.IndexOf("&qtf_securityfql:uid=") + 21, (LogLine.IndexOf(" HTTP/1.1\"") - LogLine.IndexOf("&qtf_securityfql:uid=")) - 21);
                    String UserID =LogLine.Substring(LogLine.IndexOf("&qtf_securityfql:uid=") + 21, LogLine.IndexOf("&rpf_security:uid=") - LogLine.IndexOf("&qtf_securityfql:uid=") - 21);
                    if (UserID.Length > 0)
                    {
                        Users.Add(Encoding.Default.GetString(System.Convert.FromBase64String(UserID)));
                    }

                    //Add Monthly Dates
                    DateTime dt = GetQueryDate(LogLine);
                    Dates.Add(dt.Month + "/" + dt.Year);


                    //Top Queries
                    string Query = LogLine.Substring(LogLine.IndexOf("&query=") + 7, LogLine.IndexOf("&spell=") - 7 - LogLine.IndexOf("&query="));
                    Query = HttpUtility.UrlDecode(Query);

                    if (Query.Contains("qtf_parsekw:"))
                    {
                        Query = Query.Substring(Query.IndexOf("qtf_parsekw:"), Query.IndexOf("qtf_parsekw:") - Query.Length);
                    }
                    if (Query.Length > 0)
                    {
                        Queries.Add(Query);
                    }

                    //Top Sites
                    if (LogLine.Contains("<starts-with><string text=\""))
                    {
                        String Sites1 = LogLine.Substring(LogLine.IndexOf("<starts-with><string text=\"") + 27, LogLine.Length - LogLine.IndexOf("<starts-with><string text=\"") - 27);
                        String Sites2 = Sites1.Substring(0, Sites1.IndexOf("\">"));
                        if (Sites2.Length > 0)
                        {
                            Sites.Add(Sites2);
                        }
                    }
                }
            }
            catch (Exception EX)
            {
                MessageBox.Show(EX.ToString());
            }

            return;
        }

        public void PostProcess()
        {
            try
            {
                // Write total Queries to Label
                lbl_TotalQueries.Text = "Total Queries: " + TotalQueries.ToString();

                // Write Unique Users to Label
                List<String> DistinctUsers = Users.Distinct().ToList();
                lbl_TotalUsers.Text = "Total Users: " + DistinctUsers.Count().ToString();

                //Write Average Queries Per User
                lbl_AverageQueriesPerUser.Text = "Average Queries Per User: " + Convert.ToString(TotalQueries / DistinctUsers.Count());

                // Average count of queries per user
                var UserQueries = Users.GroupBy(x => x)
                    .Select(g => new { Value = g.Key, Count = g.Count() })
                    .OrderByDescending(x => x.Count);

                foreach (var x in UserQueries)
                {
                    int n = dgv_UserQueryCount.Rows.Add();
                    dgv_UserQueryCount.Rows[n].Cells[0].Value = x.Value;
                    dgv_UserQueryCount.Rows[n].Cells[1].Value = x.Count;
                }

                // Monthly Statistics
                var months = Dates.GroupBy(x => x)
                .Select(g => new { Value = g.Key, Count = g.Count() })
                .OrderByDescending(x => x.Count);

                foreach (var x in months)
                {
                    int n = dgv_MonthlyStats.Rows.Add();
                    dgv_MonthlyStats.Rows[n].Cells[0].Value = x.Value;
                    dgv_MonthlyStats.Rows[n].Cells[1].Value = x.Count;
                }

                // Top Queries
                var TopQueries = Queries.GroupBy(x => x)
                    .Select(g => new { Value = g.Key, Count = g.Count() })
                    .OrderByDescending(x => x.Count);

                foreach (var x in TopQueries)
                {
                    int n = dgv_TopQueries.Rows.Add();
                    dgv_TopQueries.Rows[n].Cells[0].Value = x.Value;
                    dgv_TopQueries.Rows[n].Cells[1].Value = x.Count;
                }

                // Top Sites
                var TopSites = Sites.GroupBy(x => x)
                    .Select(g => new { Value = g.Key, Count = g.Count() })
                    .OrderByDescending(x => x.Count);

                foreach (var x in TopSites)
                {
                    int n = dgv_TopSites.Rows.Add();
                    dgv_TopSites.Rows[n].Cells[0].Value = x.Value;
                    dgv_TopSites.Rows[n].Cells[1].Value = x.Count;
                }

                //Clean Up Lists to free memory.
                Users.Clear();
                Dates.Clear();
                Queries.Clear();
                Sites.Clear();

            }
            catch (Exception EX)
            {
                MessageBox.Show(EX.ToString());
            }
            return;
        }

        //Code Borred from Mikael Svensons FAST Query Logger
        private static DateTime GetQueryDate(string line)
        {
            int dateStart = line.IndexOf('[') + 1;
            int dateEnd = line.IndexOf(']');
            string date = line.Substring(dateStart, dateEnd - dateStart);

            DateTime dt;
            if (!DateTime.TryParseExact(date, @"dd\/MMM\/yyyy:HH:mm:ss zz00", null, DateTimeStyles.None, out dt))
            {
                if (!DateTime.TryParseExact(date, @"dd\/MMM\/yyyy:HH:mm:ss +zz00", null, DateTimeStyles.None, out dt))
                {
                    if (!DateTime.TryParseExact(date, @"dd\/MMM\/yyyy:HH:mm:ss +zz00", null, DateTimeStyles.None, out dt))
                    {
                        if (!DateTime.TryParse(date, null, DateTimeStyles.None, out dt))
                        {
                            dt = DateTime.Now;
                        }
                    }
                }
            }
            return dt;
        }

        private void lnk_SL_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Process.Start(e.Link.LinkData as string);

        }
    }
}